package com.itjeffrey.autocode.config;

import com.itjeffrey.autocode.constant.SysConstant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * swagger2配置
 * 项目启用，访问：http://localhost:9001/swagger-ui.html
 */
//@Profile(value = {"dev"}) //指定swagger2适用环境
@Configuration
@EnableSwagger2 //启用Swagger2
public class Swagger2Config {

    @Resource
    private Swagger2Properties swagger2Properties;

    @Bean
    public Docket docket(){
        List<Parameter> params = new ArrayList<>();
        params.add(new ParameterBuilder().name("id").defaultValue("10001").description("唯一标识").parameterType("header")
                .modelRef(new ModelRef("string")).required(false).build());
        return new Docket(DocumentationType.SWAGGER_2)
            //配置Swagger2文档基本信息
            .apiInfo(swaggerApiInfo())
            //swagger2启用开关
            .enable(swagger2Properties.getEnabled())
            //select()方法返回一个ApiSelectorBuilder实例暴露Swagger2展示需要控制的接口
            .select()
            //扫描带@Api注解的类，也可以通过basePackage()配置api接口包扫描路径
            //.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
            //扫描basePackage包下的所有@Api注解标识的API类
            .apis(RequestHandlerSelectors.basePackage(SysConstant.SWAGGER2_PACKAGE))
            //配置需要加入swagger2文档的请求url路径
            .paths(PathSelectors.any())
            .build()
            //配置全局方法参数
            .globalOperationParameters(params)
            //配置Swagger2全局参数
            .securitySchemes(securitySchemes())
            //配置全局参数的接口适用范围
            .securityContexts(securityContexts());
    }

    /**
     * 配置 Swagger2 ApiInfo 文档基本信息
     * @return ApiInfo
     */
    private ApiInfo swaggerApiInfo(){
        return new ApiInfoBuilder()
            //文档标题
            .title("AutoCode接口文档")
            //文档描述
            .description("API Document for Spring Boot 2.X AutoCode Project! If test, try to 'Authorize'~")
            //设置文档的License信息
            //.termsOfServiceUrl("http://localhost:9001")
            //文档版本号
            .version("v1.0")
            .build();
    }

    /**
     * Swagger2全局参数配置
     * 针对本系统，需对每一次请求添加类型为header名为Authentication和RefreshToken两个认证请求头参数，实现全局接口测试
     * @return apiKeys
     */
    private List<ApiKey> securitySchemes() {
        ArrayList<ApiKey> apiKeys = new ArrayList<>();
        ApiKey tokenApiKey = new ApiKey("Authentication", "Authentication", "header");
        ApiKey refreshTokenApiKey = new ApiKey("RefreshToken", "RefreshToken", "header");
        apiKeys.add(tokenApiKey);
        apiKeys.add(refreshTokenApiKey);
        return apiKeys;
    }

    /**
     * 配置全局参数的接口适用范围
     * 通过正则表达式设置需要使用参数的接口路径（或排除不需要使用参数的接口）
     * eg: 本系统中，所有包含login和register路径的接口都不使用securitySchemes全局参数
     * @return securityContexts
     */
    private List<SecurityContext> securityContexts() {
        ArrayList<SecurityContext> securityContexts = new ArrayList<>();
        SecurityContext securityContext = SecurityContext.builder()
            .securityReferences(getSecurityReferences())
            .forPaths(PathSelectors.regex("^(?!(login|register)).*$"))
            .build();
        securityContexts.add(securityContext);
        return securityContexts;
    }

    /**
     * SecurityReference Lists
     * 需对每一次请求添加Authentication和RefreshToken两个认证请求头参数，实现全局接口测试
     * @return securityReferences
     */
    private List<SecurityReference> getSecurityReferences() {
        ArrayList<SecurityReference> securityReferences = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        SecurityReference securityReference1 = new SecurityReference("Authentication", authorizationScopes);
        SecurityReference securityReference2 = new SecurityReference("RefreshToken", authorizationScopes);
        securityReferences.add(securityReference1);
        securityReferences.add(securityReference2);
        return securityReferences;
    }

}
